﻿using System.Collections.Generic;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Mvc.Html;
using ExtendedMvc.Ajax;
using ExtendedMvc.Common.Diagnostics;

namespace ExtendedMvc {
	/// <summary>
	/// Builds a strongly typed  form in a view.
	/// </summary>
	/// <typeparam name="TModel">The type of the model.</typeparam>
	public class ModelViewForm<TModel> : MvcForm where TModel : class {
		private static object _formNumKey;
		private ViewContext _view;
		private IModelViewHelper<TModel> _helper;

		/// <summary>
		/// Initializes the <see cref="ModelViewForm&lt;TModel&gt;"/> class.
		/// </summary>
		static ModelViewForm() {
			_formNumKey = new object();
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ModelViewForm&lt;TModel&gt;"/> class.
		/// </summary>
		/// <param name="helper">The helper.</param>
		public ModelViewForm(IModelViewHelper<TModel> helper)
			: base(helper.ViewContext) {
			_helper = helper;
			_view = _helper.ViewContext;
			Id = FormIdGenerator();
		}

		/// <summary>
		/// Gets the view context.
		/// </summary>
		/// <value>The view context.</value>
		public ViewContext ViewContext { get { return _view; } }

		/// <summary>
		/// Gets the helper.
		/// </summary>
		/// <value>The helper.</value>
		public IModelViewHelper<TModel> Helper { get { return _helper; } }

		/// <summary>
		/// Gets or sets the id.
		/// </summary>
		/// <value>The id.</value>
		public string Id { get; private set; }

		/// <summary>
		/// Generate the form id.
		/// </summary>
		/// <returns></returns>
		private string FormIdGenerator() {
			object count = _view.HttpContext.Items[_formNumKey];
			int num = (count != null) ? ((int)count + 1) : 0;
			_view.HttpContext.Items[_formNumKey] = num;
			return string.Format(CultureInfo.InvariantCulture, "form{0}", new object[] { num });
		}


		/// <summary>
		/// Creates the specified HTML form.
		/// </summary>
		/// <param name="html">The HTML.</param>
		/// <param name="formAction">The form action.</param>
		/// <param name="method">The method.</param>
		/// <param name="htmlAttributes">The HTML attributes.</param>
		/// <returns></returns>
		public static ModelViewForm<TModel> Create(ModelViewHtmlHelper<TModel> html, string formAction, FormMethod method = FormMethod.Post, IDictionary<string, object> htmlAttributes = null) {
			Check.Argument.IsNotNull(formAction, "formAction");
			var form = new ModelViewForm<TModel>(html);
			var Builder = new TagBuilder("form");
			if (htmlAttributes != null) Builder.MergeAttributes<string, object>(htmlAttributes);
			Builder.MergeAttribute("action", formAction);
			Builder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
			Builder.GenerateId(form.Id);
			form.ViewContext.Writer.Write(Builder.ToString(TagRenderMode.StartTag));
			form.ViewContext.FormContext.FormId = form.Id;
			return form;
		}

		/// <summary>
		/// Creates the specified ajax form.
		/// </summary>
		/// <param name="ajax">The ajax.</param>
		/// <param name="formAction">The form action.</param>
		/// <param name="ajaxOptions">The ajax options.</param>
		/// <param name="ajaxAttributes">The ajax attributes.</param>
		/// <returns></returns>
		public static ModelViewForm<TModel> Create(ModelViewAjaxHelper<TModel> ajax, string formAction, AjaxOptions ajaxOptions = null, IDictionary<string, object> htmlAttributes = null) {
			var form = new ModelViewForm<TModel>(ajax);
			var Builder = new TagBuilder("form");
			if (htmlAttributes != null) Builder.MergeAttributes<string, object>(htmlAttributes);
			Builder.MergeAttribute("action", formAction, true);
			Builder.MergeAttribute("method", HtmlHelper.GetFormMethodString(FormMethod.Post), true);
			Builder.GenerateId(form.Id);
			Builder.MergeAttribute("onclick", JavaScriptHelper.ClickEventHandler, true);
			Builder.MergeAttribute("onsubmit", JavaScriptHelper.GenerateAjaxScript(ajaxOptions == null ? new AjaxOptions() : ajaxOptions, JavaScriptHelper.SubmitEventHandler), true);
			form.ViewContext.Writer.Write(Builder.ToString(TagRenderMode.StartTag));
			form.ViewContext.FormContext.FormId = form.Id;
			return form;
		}
	}
}
